/*
 * SplashScreen.java  0.4.0 / Oct 26, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.swing;

import java.net.URL;

import com.cute4j.swing.events.SwingEvent;
import com.cute4j.swing.graphics.Graphics;
import com.cute4j.swing.graphics.Image;

/**
 * Splash Screen Component.
 *
 * @cute4j.native
 *    generate="header"

 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
public class SplashScreen extends Window {

// Public Static Fields. -------------------------------------------------------

  /**
   * Default splash time (the value is {@value}).
   */
  public static final int DEFAULT_SPLASH_TIME = 1700;

// Private Static Fields. ------------------------------------------------------

  private static DefaultSplashScreen splashScreen; // NOPMD
  private static long startTime;

// Public Constructors. --------------------------------------------------------

  /**
   * Constructs new ToolWindow object.
   */
  public SplashScreen() {
    super(null, null);
    windowType = TYPE_SPLASH_SCREEN;
    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
  }

// Public Static Methods. ------------------------------------------------------

  /**
   * Creates default splash using specified image.
   *
   * @param imageName the image name
   */
  public static void create(String imageName) {
    create(imageName, null, 0);
  }

  /**
   * Creates default splash using specified image.
   *
   * @param imageName the image name
   * @param startMessage the start message
   * @param updatesNumber the number of splash updates
   */
  public static void create(String imageName, String startMessage,
                            int updatesNumber) {
    if (splashScreen != null) {
      splashScreen.dispose();
    }
    startTime = System.currentTimeMillis();
    splashScreen = new DefaultSplashScreen(Swing.crateImage(imageName),
                                           startMessage, updatesNumber);
  }

  /**
   * Creates default splash using specified image.
   *
   * @param image the image
   */
  public static void create(Image image) {
    create(image,  null, 0);
  }

  /**
   * Creates default splash using specified image.
   *
   * @param image the image
   * @param startMessage the start message
   * @param updatesNumber the number of splash updates
   */
  public static void create(Image image, String startMessage,
                            int updatesNumber) {
    if (splashScreen != null) {
      splashScreen.dispose();
    }
    startTime = System.currentTimeMillis();
    splashScreen = new DefaultSplashScreen(image, startMessage, updatesNumber);
  }

  /**
   * Creates default splash using specified image.
   *
   * @param location the image location
   */
  public static void create(URL location) {
    create(location,  null, 0);
  }

  /**
   * Creates default splash using specified image.
   *
   * @param location the image location
   * @param startMessage the start message
   * @param updatesNumber the number of splash updates
   */
  public static void create(URL location, String startMessage,
                            int updatesNumber) {
    if (splashScreen != null) {
      splashScreen.dispose();
    }
    startTime = System.currentTimeMillis();
    splashScreen = new DefaultSplashScreen(Swing.crateImage(location),
                                           startMessage, updatesNumber);
  }

  /**
   * Updates the splash.
   *
   * @param message the update message
   */
  public static void update(String message) {
    if (splashScreen != null) {
      splashScreen.updateMessage(message);
    }
  }

  /**
   * Finishes the splash.
   *
   * @param window the window to show
   * @param message the finishing message
   */
  public static void finish(Window window, String message) {
    if (splashScreen != null) { // NOPMD
      splashScreen.updateMessage(message);
      long time = System.currentTimeMillis() - startTime;
      time = DEFAULT_SPLASH_TIME - time;
      if (time > 0) {
        try {
          Thread.sleep(time);
        } catch (InterruptedException ex) {
          // empty catch block
        }
      }
      if (window != null) {
        window.setVisible(true);
      }
      splashScreen.setVisible(false);
      splashScreen.dispose();
      splashScreen = null;
    }
  }

// Overridden Methods. ---------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  public void update() {
    super.update();
    Swing.flushEvents();
  }

// Package-Private Native Methods. ---------------------------------------------

  native long _create();

// Inner Classes. --------------------------------------------------------------

  /**
   * Basic Splash Screen.
   */
  public static class DefaultSplashScreen extends SplashScreen {

    private Image image;
    private final String message;
    private final int stepCount;
    private int currentStep; // NOPMD
    private Label messageLabel;
    private ProgressBar progressBar;

    /**
     * Constructs new BasicSplashScreen object.
     *
     * @param image the splash image
     * @param message the start message
     * @param stepCount the number of splash updates
     */
    public DefaultSplashScreen(Image image, String message, int stepCount) {
      if (image == null) {
        throw new IllegalArgumentException("Null image");
      }
      this.image = image;
      this.message = message;
      this.stepCount = stepCount + 1;
      setSize(image.getWidth(), image.getHeight());
      setLocationRelativeTo(null);
      buildSplash();
      enableEvents(SwingEvent.PAINT_EVENT_MASK);
      setVisible(true);
    }

    /**
     * Builds splash.
     */
    protected void buildSplash() {
      if ((message != null) && (stepCount > 0)) {
        progressBar = new ProgressBar(0, stepCount);
        progressBar.setName("splashProgressBar");
        int width = getWidth() - 20;
        int height = getHeight();
        int progressBarHeight = progressBar.getPreferredSize().getHeight() - 2;
        progressBar.setBounds(10, height - progressBarHeight - 37, width,
                              progressBarHeight);
        add(progressBar);
        messageLabel = new Label(message);
        progressBar.setName("splashLabel");
        int messageLabelHeight = messageLabel.getPreferredSize().getHeight();
        messageLabel.setBounds(11, progressBar.getY() - messageLabelHeight - 2,
                               width, messageLabelHeight);
        add(messageLabel);
      }
    }

    /**
     * Updates splash message.
     *
     * @param message the splash message
     */
    public void updateMessage(String message) {
      if (currentStep < stepCount) {
        messageLabel.setText(message);
        progressBar.setValue(++currentStep);
        update();
      }
    }

    /**
     * {@inheritDoc}
     */
    protected void paintComponent(Graphics g) {
      g.drawImage(image, 0, 0);
    }

    void destroyComponent() {
      super.destroyComponent();
      image.flush();
      image = null;
    }

  }

}
